package com.wchen.gdoc.generate.resource.analysis;

import com.sun.javadoc.*;
import com.wchen.gdoc.generate.resource.structure.*;
import java.util.*;


/**
 * 类结构解析
 *
 * @author  wchen
 * @date    2019/11/7
 */
public class ClassDocAnalysis extends AbsParentAnalysis {

    /**
     * 解析ClassDoc
     *
     * @param classDoc
     * @return
     */
    public ClassStructure analysisClassDoc(ClassDoc classDoc){
        LOGGER.info(String.format("analysisClassDoc begin.  className:%s", classDoc.simpleTypeName()));
        ClassStructure classStructure = new ClassStructure();
        //注解、注释
        List<AnnotationStructure> classAnnotationList = analysisAnnotationDoc(classDoc.annotations());
        String className = classDoc.simpleTypeName();
        String classType = classDoc.qualifiedTypeName();
        String commentText = classDoc.commentText();
        List<TagStructure> tagStructures = extractTag(classDoc.typeParamTags(), classDoc.tags(), null);

        //方法
        List<MethodStructure> methodStructureList = new ArrayList<>();
        MethodDoc[] methodDocs = classDoc.methods();
        for (MethodDoc methodDoc : methodDocs) {
            try {
                MethodStructure methodStructure = analysisMethodDoc(methodDoc);
                methodStructure.setClassStructure(classStructure);
                methodStructureList.add(methodStructure);
            }catch (Exception e){
                LOGGER.error(String.format("analysisMethodDoc error ... [%s]", classDoc.qualifiedName() + "." + methodDoc.name()));
                e.printStackTrace();
            }
        }

        //结构组装
        classStructure.setClassName(className);
        classStructure.setClassAnnotationList(classAnnotationList);
        classStructure.setCommentText(commentText);
        classStructure.setTagStructureList(tagStructures);
        classStructure.setClassType(classType);
        classStructure.setMethodStructureList(methodStructureList);
        return classStructure;
    }


    /**
     * 解析methodDoc
     *
     * @param methodDoc
     * @return
     */
    private MethodStructure analysisMethodDoc(MethodDoc methodDoc) {
        LOGGER.info(String.format("analysisMethodDoc begin.  methodName:%s, description:%s", methodDoc.name(), methodDoc.commentText()));
        MethodStructure methodStructure = new MethodStructure();

        //注解、注释
        String commentText = methodDoc.commentText();
        String methodName = methodDoc.name();
        List<AnnotationStructure> annotationStructures = analysisAnnotationDoc(methodDoc.annotations());
        Map<String, String> paramTagMap = new HashMap<>();
        List<TagStructure> tagStructures = extractTag(methodDoc.paramTags(), methodDoc.tags(), paramTagMap);

        LOGGER.info(String.format("analysisMethodReturned begin.  methodName:%s ", methodDoc.name()));
        //返回结构
        ReturnedStructure returnedStructure = null;
        if (Objects.nonNull(methodDoc.returnType().asClassDoc())){
            FieldStructure returnedFieldStructure = executeAnalysis(methodDoc.returnType(), Boolean.FALSE);
            // TODO: 2019/7/12  暂不支持的数据类型
            if(Objects.nonNull(returnedFieldStructure)){
                returnedStructure = new ReturnedStructure(returnedFieldStructure);
                String returnedCommentText = methodDoc.tags("return").length < 1 ? "" : methodDoc.tags("return")[0].text();
                returnedStructure.setReturnedCommentText(returnedCommentText);
            }
        }

        LOGGER.info(String.format("analysisMethodParameters begin.  methodName:%s ", methodDoc.name()));
        //入参结构
        List<ParameterStructure> parameterStructureList = new ArrayList<>();
        for (Parameter parameter : methodDoc.parameters()) {
            List<AnnotationStructure> paramAnnotationStructures = analysisAnnotationDoc(parameter.annotations());
            FieldStructure paramFieldStructure = executeAnalysis(parameter.type(), Boolean.TRUE);
            if(Objects.isNull(paramFieldStructure)){
                continue;
            }
            String parameterName = parameter.name();
            ParameterStructure parameterStructure = new ParameterStructure(paramFieldStructure, methodStructure);
            parameterStructure.setParamName(parameterName);
            parameterStructure.setParamAnnotationList(paramAnnotationStructures);
            parameterStructure.setParamCommentText(paramTagMap.get(parameterName));
            parameterStructureList.add(parameterStructure);
        }

        //结果拼装
        methodStructure.setCommentText(commentText);
        methodStructure.setMethodName(methodName);
        methodStructure.setReturned(returnedStructure);
        methodStructure.setParameterList(parameterStructureList);
        methodStructure.setMethodAnnotationList(annotationStructures);
        methodStructure.setTagStructureList(tagStructures);
        return methodStructure;
    }


    /**
     * 提取参数注释
     *
     * @param paramTags
     * @param tags
     * @param paramTagMap
     * @return
     */
    private List<TagStructure> extractTag(ParamTag[] paramTags, Tag[] tags, Map<String, String> paramTagMap){
        List<TagStructure> tagStructures = new ArrayList<>();
        for (ParamTag paramTag : paramTags) {
            TagStructure tagStructure = new TagStructure();
            tagStructure.setTagType(paramTag.name());
            tagStructure.setName(paramTag.parameterName());
            tagStructure.setCommentText(paramTag.parameterComment());
            tagStructures.add(tagStructure);
            if(Objects.nonNull(paramTagMap)) {
                paramTagMap.put(paramTag.parameterName(), paramTag.parameterComment());
            }
        }

        for (Tag tag : tags) {
            if(!"@param".equals(tag.name())){
                TagStructure tagStructure = new TagStructure();
                tagStructure.setTagType(tag.name());
                tagStructure.setCommentText(tag.text());
                tagStructures.add(tagStructure);
            }
        }
        return tagStructures;
    }
}
